#include "sampler.h"
#include "GlobalDefine.h"
#include <cmath>
#include <random>
#include <ctime>

namespace mray{

	void JitteredSampler::GenerateSamples(int nSamples, int nSets){
		m_samples.clear();
		m_nSamples = nSamples;
		m_nSets = nSets;
		m_samples.resize(nSamples * nSets);
		srand((int)time(nullptr));
		int n = (int)sqrt(nSamples);
		int attr = 0;

		std::mt19937 d;
		std::uniform_real_distribution<float> e(0.f, 1.f);
		d.seed(reinterpret_cast<int>(this));

		for(int p = 0; p < nSets; p++)
			for(int  j = 0; j < n; j++)
				for(int k = 0; k < n; k++)
					m_samples[attr++] = vec2( (k+e(d))/n , (j+e(d))/n );
	}

	void DiskSampler::GenerateSamples(int num_samples, int num_sets){
		m_samples.clear();
		m_pBaseSpl->GenerateSamples(num_samples, num_sets);
		m_nSamples = num_samples;
		m_nSets = num_sets;
		int size = num_samples * num_sets;
		m_samples.resize(size);
		float r, phi;
		vec2 sp;
		//copy form base sampler to disk_sampler sampler
		for(int attr = 0; attr < size; attr++){
			sp.x = (*m_pBaseSpl)[attr].x * 2.0f - 1.0f;
			sp.y = (*m_pBaseSpl)[attr].y * 2.0f - 1.0f;
			if(sp.x > -sp.y)
				if(sp.x > sp.y){
					r = sp.x;
					phi = sp.y/sp.x;
				}else{
					r = sp.x;
					phi = 2.0f - sp.x/sp.y;
				}
			else
				if(sp.x < sp.y){
					r = -sp.x;
					phi = 4.0f + sp.y/sp.x;
				}else{
					r = -sp.y;
					if(sp.y != 0.0f)
						phi = 6.0f - sp.y/sp.x;
					else
						phi = 0.0f;
				}
			phi *= PI/4.0f;

			m_samples[attr].x = r*cos(phi);
			m_samples[attr].y = r*sin(phi);
		}
	}

	//hemisphere sampler
	void HemisphereSampler::GenerateSamples(int nSamples, int nSets, float exp){
		m_samples.clear();
		nSamples = nSamples;
		nSets = nSets;

		m_pBaseSpl->GenerateSamples(nSamples, nSets);
		int size = nSamples * nSets;
		m_samples.resize(size);
		for(int attr = 0; attr < size; attr++){
			const vec2& p = m_pBaseSpl->GetSample(attr, 0);
			float cos_phi = cos(2.0f * PI * p.x);
			float sin_phi = sin(2.0f * PI * p.x);
			float cos_theta = pow(1.0f-p.y, 1.0f/(exp+1.0f));
			float sin_theta = sqrt(1.0f-cos_theta*cos_theta);
			m_samples[attr].x = sin_theta * cos_phi;
			m_samples[attr].y = sin_theta * sin_phi;
			m_samples[attr].z = cos_theta;
		}
	}

	void AverageSampler::GenerateSamples(int num_samples, int num_sets)
	{
		m_samples.clear();
		m_nSamples = num_samples;
		m_nSets = 1;
		m_samples.resize(num_samples * num_sets);
		int n = (int)sqrt(num_samples);
		int attr = 0;
		for(int y = 0; y < n; y++)
			for(int x = 0; x < n; x++ )
				m_samples[attr++] = vec2((x+0.5f)/n, (y+0.5f)/n);
	}

	void RandomSampler::GenerateSamples(int num_samples, int num_sets)
	{
		m_samples.clear();
		m_nSamples = num_samples;
		m_nSets = num_sets;
		int size = num_samples * num_sets;
		m_samples.resize( size );
		std::mt19937 d;
		std::uniform_real_distribution<float> e(0.f, 1.f);
		d.seed(reinterpret_cast<int>(this));
		for(int attr = 0; attr < size; attr++)
			m_samples[attr] = vec2(e(d), e(d));
	}

	void MultiJitteredSampler::GenerateSamples(int num_samples, int num_sets)
	{
		//TODO
	}

}